fn brain_luck(code: &str, input: Vec<u8>) -> Vec<u8> {
  let code = code.as_bytes();
  let mut input = input.into_iter();
  let mut output = vec![];
  let mut data = [0u8; 5000];
  let mut cp = 0;
  let mut dp = 0;
  while cp < code.len() {
    match code[cp] {
      b'>' => dp += 1,
      b'<' => dp -= 1,
      b'+' => data[dp] = data[dp].wrapping_add(1),
      b'-' => data[dp] = data[dp].wrapping_sub(1),
      b'.' => output.push(data[dp]),
      b',' => data[dp] = input.next().expect("input"),
      b'[' if data[dp] == 0 => cp += jump(code[cp..].iter()),
      b']' if data[dp] != 0 => cp -= jump(code[0..cp + 1].iter().rev()),
      _ => {},
    }
    cp += 1;
  }
  output
}

fn jump<'a, I: 'a>(code: I) -> usize
where I: Iterator<Item=&'a u8>
{
  let mut n = 0;
  for (i, &c) in code.enumerate() {
    if c == b'[' { n += 1; }
    if c == b']' { n -= 1; }
    if n == 0 {
    return i;
    }
  }
  unreachable!();
}

fn brain_luck_1(code: &str, input: Vec<u8>) -> Vec<u8> {
    Machine::new(input, code).go()
}


#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn example_tests() {
        // Echo until byte 255 encountered
        assert_eq!(String::from_utf8(brain_luck(",+[-.,+]", ez_vec("Codewars", 255))).unwrap(), "Codewars");
        // Echo until byte 0 encountered
        assert_eq!(String::from_utf8(brain_luck(",[.[-],]", ez_vec("Codewars", 0))).unwrap(), "Codewars");
        // Multiply two numbers
        assert_eq!(brain_luck(",>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.", vec![8, 9]), vec![72]);
    }
    
    // Takes a static string and a terminating byte and returns an owned Vec<u8> for convenience
    // Without it, character-based tests are a pain   
    fn ez_vec(s: &str, i: u8) -> Vec<u8> {
      let mut v = s.to_string().into_bytes();
      v.push(i);
      v
    }   
}
